# -*- coding: utf-8 -*-

#-------------------------------------------------------------------------
# drawElements Quality Program utilities
# --------------------------------------
#
# Copyright 2017 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#-------------------------------------------------------------------------

import operator as op
from genutil import *
from collections import OrderedDict

VECTOR_TYPES	= ["vec2", "vec3", "vec4", "ivec2", "ivec3", "ivec4"]
PRECISION_TYPES = ["mediump"]
SWIZZLE_NAMES	= ["xyzw"]

s_swizzleCaseTemplate = """
case ${{NAME}}
	version 300 es
	values
	{
		${{VALUES}}
	}

	both ""
		#version 300 es
		precision mediump float;

		${DECLARATIONS}

		void main()
		{
			${SETUP}
			${{OP}}
			${OUTPUT}
		}
	""
end
"""[1:]

def getDataTypeScalarSize (dt):
	return {
		"vec2":		2,
		"vec3":		3,
		"vec4":		4,
		"ivec2":	2,
		"ivec3":	3,
		"ivec4":	4,
	}[dt]

def getSwizzlesForWidth(width):
	if (width == 2):
		return [(0, ),
			(0,0), (0,1), (1,0),
			(1,0,1), (0,1,0,0), (1,0,1,0)]
	elif (width == 3):
		return [(0,), (2,),
			(0,2), (2,2),
			(0,1,2), (2,1,0), (0,0,0), (2,2,2), (2,2,1), (1,0,1), (0,2,0),
			(0,1,1,0), (2,0,1,2)]
	elif (width == 4):
		return [(0,), (3,),
			(3,0), (3,2),
			(3,3,3), (1,1,3), (3,2,1),
			(0,1,2,3), (3,2,1,0), (0,1,0,1), (1,2,2,1), (3,0,3,3), (0,1,0,0), (2,2,2,2)]
	else:
		assert False

def operatorToSymbol(operator):
	if operator == "add":		return "+"
	if operator == "subtract":	return "-"
	if operator == "multiply":	return "*"
	if operator == "divide":	return "/"

def rotate(l, n) :
	return l[n:] + l[:n]

class SwizzleCase(ShaderCase):
	def __init__(self, name, swizzle1, swizzle2, inputs1, inputs2, operator, outputs):
		self.name	= name
		self.swizzle1	= swizzle1
		self.swizzle2	= swizzle2
		self.inputs	= inputs1 + inputs2
		self.outputs	= outputs
		self.op		= "out0 = in0.%s %s in1.%s;" % (swizzle1, operator, swizzle2)

	def __str__(self):
		params = {
			"NAME":		self.name,
			"VALUES":	genValues(self.inputs, self.outputs),
			"OP":		self.op
		}
		return fillTemplate(s_swizzleCaseTemplate, params)


# CASE DECLARATIONS
inFloat = [Scalar(x) for x in [0.0, 1.0, 2.0, 3.5, -0.5, -20.125, 36.8125]]
inInt	= [Scalar(x) for x in [0, 1, 2, 5, 8, 11, -12, -66, -192, 255]]

inVec4	= [
	Vec4(0.1, 0.5, 0.75, 0.825),
	Vec4(1.0, 1.25, 1.125, 1.75),
	Vec4(-0.5, -2.25, -4.875, 9.0),
	Vec4(-32.0, 64.0, -51.0, 24.0),
	Vec4(-0.75, -1.0/31.0, 1.0/19.0, 1.0/4.0),
]

inVec3	= toVec3(inVec4)
inVec2	= toVec2(inVec4)

inIVec4 = toIVec4(
	[
	    Vec4(-1, 1, -1, 1),
	    Vec4(1, 2, 3, 4),
	    Vec4(-1, -2, -4, -9),
	]
)

inIVec3 = toIVec3(inIVec4)
inIVec2 = toIVec2(inIVec4)

INPUTS = OrderedDict([
	("float",	inFloat),
	("vec2",	inVec2),
	("vec3",	inVec3),
	("vec4",	inVec4),
	("int",		inInt),
	("ivec2",	inIVec2),
	("ivec3",	inIVec3),
	("ivec4",	inIVec4),
])

OPERATORS = OrderedDict([
	("add",		op.add),
	("subtract",	op.sub),
	("multiply",	op.mul),
	("divide",	op.div),
])

vectorSwizzleGroupCases = {
	"add":		[],
	"subtract" :	[],
	"multiply" :	[],
	"divide" :	[],
}

allCases = []

for operator in OPERATORS:
	for dataType in VECTOR_TYPES:
		scalarSize = getDataTypeScalarSize(dataType)
		for precision in PRECISION_TYPES:
			for swizzleComponents in SWIZZLE_NAMES:
				for swizzleIndices in getSwizzlesForWidth(scalarSize):
					swizzle1 = "".join(map(lambda x: swizzleComponents[x], swizzleIndices))

					swizzle2 = rotate(swizzle1, 1)
					rotatedSwizzleIndices = rotate(swizzleIndices, 1)

					operands1 = INPUTS[dataType]
					operands2 = INPUTS[dataType]  # these input values will be swizzled

					outputs = map(lambda x, y: OPERATORS[operator](x.swizzle(swizzleIndices), y.swizzle(rotatedSwizzleIndices)), operands1, operands2)
					outType = outputs[0].typeString()
					caseName = "%s_%s_%s_%s" % (precision, dataType, swizzle1, swizzle2)

					case = SwizzleCase(	caseName,
								swizzle1,
								swizzle2,
								[("%s in0" % dataType, operands1)],
								[("%s in1" % dataType, operands2)],
								operatorToSymbol(operator),
								[("%s out0" % outType, outputs)])

					vectorSwizzleGroupCases[operator].append(case)

	allCases.append(CaseGroup("vector_" + operator, "Vector swizzle math operations", vectorSwizzleGroupCases[operator]))

if __name__ == "__main__":
	print("Generating shader case files.")
	writeAllCases("swizzle_math_operations.test", allCases)
